package com.jebel.framework.gateway.gateway;

import com.jebel.framework.gateway.handler.LoginAuthHandler;
import com.jebel.framework.gateway.handler.ParamFilterHandler;
import com.jebel.framework.gateway.handler.PublicServiceFilterHandler;
import com.jebel.framework.gateway.handler.ServiceFilterHandler;
import com.jebel.framwork.common.response.RespBodyBuilder;
import com.jebel.framwork.common.response.RespCode;
import com.jebel.framwork.common.util.JsonUtil;
import com.jebel.framwork.common.util.StringUtil;
import com.jebel.framwork.common.util.VertxSendFutureUtil;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.MultiMap;
import io.vertx.core.eventbus.DeliveryOptions;
import io.vertx.core.http.HttpHeaders;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.auth.KeyStoreOptions;
import io.vertx.ext.auth.jwt.JWTAuth;
import io.vertx.ext.auth.jwt.JWTAuthOptions;
import io.vertx.ext.web.FileUpload;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.BodyHandler;
import io.vertx.ext.web.handler.LoggerHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import java.util.Set;
import java.util.concurrent.CompletableFuture;

@Component
public class GateWayVerticle extends AbstractVerticle {

    private static Logger logger = LoggerFactory.getLogger(GateWayVerticle.class);

    @Autowired
    private Environment environment;

    @Override
    public void start() throws Exception {
        Router router = Router.router(vertx);
        router.route().handler(LoggerHandler.create());
        router.route().handler(BodyHandler.create());

        JWTAuthOptions jwtAuthOptions = new JWTAuthOptions();
        jwtAuthOptions.setKeyStore(new KeyStoreOptions().setPath("keystore.jceks").setPassword("secret"));
        JWTAuth jwtAuth = JWTAuth.create(vertx, jwtAuthOptions);

        router.route("/mstx/pr/*").handler(ServiceFilterHandler.create(vertx));
        router.route("/mstx/prLong/*").handler(ServiceFilterHandler.create(vertx));
        router.route("/mstx/prLong/gateway.do").handler(this::doPrLongEventBusGateway);

        router.route("/mstx/pr/gateway.do").handler(ParamFilterHandler.create(vertx, environment));
        router.route("/mstx/pr/gateway.do").handler(LoginAuthHandler.create(vertx, jwtAuth));
        router.route("/mstx/pr/gateway.do").handler(PublicServiceFilterHandler.create(vertx));
        router.route("/mstx/pr/gateway.do").handler(this::doPrEventBusGateway);

        //支付回调
        router.route("/mstx/payback/toOrder").handler(this::doPaybackToorder);
        //退款回调
        router.route("/mstx/refundback/toOrder").handler(this::doRefundbackToorder);

        //文件上传
        router.route("/mstx/upload/file").handler(this::doUploadFileEventBusGateway);
        router.route("/mstx/download/file").handler(this::doDownloadFileEventBusGateway);

        Integer port = Integer.valueOf(environment.getProperty("server.port", "6060"));
        vertx.createHttpServer().requestHandler(router::accept).listen(port);
    }

    private void doDownloadFileEventBusGateway(RoutingContext context) {
        HttpServerRequest httpServerRequest = context.request();
        httpServerRequest.response().putHeader("Access-Control-Allow-Origin", "*");
        httpServerRequest.response().putHeader("Access-Control-Allow-Methods", "GET");
        httpServerRequest.response().putHeader("Access-Control-Allow-Headers", "x-requested-with,content-type");
        String method = context.request().method().name();
        if (method.equals("OPTIONS")) {
            httpServerRequest.response().setStatusCode(200).end(RespBodyBuilder.toCommonSuccess());
            return;
        }
        httpServerRequest.exceptionHandler(exceptionHandler -> {
            logger.error(exceptionHandler.getMessage());
            reqError(httpServerRequest, 500, "文件异常");
            return;
        });
        HttpMethod httpMethod = httpServerRequest.method();
        String httpPath = httpServerRequest.path();
        logger.info(httpServerRequest.host());
        logger.info(httpServerRequest.method().name());
        logger.info(httpServerRequest.path());
        logger.info(httpServerRequest.query());
        if (httpMethod.equals(HttpMethod.GET) && httpPath.equals("/mstx/download/file")) {
            MultiMap multiMap = httpServerRequest.params();
            if (multiMap == null || multiMap.isEmpty()) {
                reqError(httpServerRequest, 404, "文件路径有误");
                return;
            }
            String path = multiMap.get("path");
            if (StringUtil.isEmpty(path) || vertx.fileSystem().existsBlocking(path)) {
                reqError(httpServerRequest, 404, "文件不存在");
                return;
            }
            DeliveryOptions options = new DeliveryOptions();
            options.setSendTimeout(Integer.valueOf(environment.getProperty("vertx.sendimeout", "10000")));
            CompletableFuture<String> future = new CompletableFuture<>();
            VertxSendFutureUtil.vertxSendFuture(vertx, "report.qryPath", new JsonObject().put("path", path), options, future);
            future.whenComplete((d, e) -> {
                JsonObject dd = new JsonObject(d);
                if (dd.getInteger("code") == 10500) {
                    reqError(httpServerRequest, 404, dd.getJsonObject("data").getString("errorMsg"));
                    return;
                }
                logger.info(dd.getJsonObject("data").getString("path"));
                httpServerRequest.response().sendFile(dd.getJsonObject("data").getString("path"));
            });
        } else {
            reqError(httpServerRequest, 404, "文件路径有误");
        }

    }

    private void doUploadFileEventBusGateway(RoutingContext context) {
        HttpServerResponse httpServerResponse = context.response();
        httpServerResponse.putHeader("Content-Type", "application/json;charset=UTF-8");
        httpServerResponse.putHeader("Access-Control-Allow-Origin", "*");
        httpServerResponse.putHeader("Access-Control-Allow-Methods", "POST,GET");
        httpServerResponse.putHeader("Access-Control-Allow-Headers", "x-requested-with,content-type");
        String method = context.request().method().name();
        if (method.equals("OPTIONS")) {
            httpServerResponse.setStatusCode(200).end(RespBodyBuilder.toCommonSuccess());
            return;
        }
        String content_type = context.request().getHeader(HttpHeaders.CONTENT_TYPE);
        logger.info(content_type);
        httpServerResponse.setChunked(true);
        logger.info(method);
        JsonObject fileUploadParam = new JsonObject();
        try {
            if (method.equals("POST")) {
                fileUploadParam.mergeIn(JsonUtil.convertMultiMap(context.request().formAttributes()));
            }
            Set<FileUpload> fileUploadSet = context.fileUploads();
            fileUploadSet.stream().forEach(fileUpload -> {
                fileUploadParam.put("uploadedFileName", fileUpload.uploadedFileName());
                logger.info(fileUpload.charSet());
                logger.info(fileUpload.contentType());
                logger.info(fileUpload.contentTransferEncoding());
                logger.info(fileUpload.fileName());
                logger.info(fileUpload.name());
                logger.info(fileUpload.uploadedFileName());
                logger.info("{}", fileUpload.size());
            });
            logger.info("doUploadFileEventBusGateway-param:{}", fileUploadParam.encode());
            DeliveryOptions options = new DeliveryOptions();
            options.setSendTimeout(Integer.valueOf(environment.getProperty("vertx.sendimeout", "10000")));
            //vertx.eventBus().send("network.fileUpload", fileUploadParam, options);
            logger.info("doUploadFileEventBusGateway-send-success");
            httpServerResponse.end(RespBodyBuilder.toCommonSuccess());
        } catch (Exception e) {
            logger.error("doUploadFileEventBusGateway-error:{}", e);
            httpServerResponse.end(RespBodyBuilder.toError(RespCode.CODE_10500));
        }
    }

    private void doRefundbackToorder(RoutingContext context) {
        HttpServerResponse response = context.response();
        response.putHeader("content-type", "application/json;charset=UTF-8");
        String method = context.request().method().name();
        logger.info("doRefundbackToorder method=" + method);
        JsonObject resp = new JsonObject();
        logger.info("doRefundbackToorder param=" + context.getBodyAsString());
        JsonObject requestBody = method.equals("POST") ? JsonUtil.parsePostBody(context.getBodyAsString()) : JsonUtil.convertMultiMap(context.request().params());
        try {
            if (requestBody == null) {
                response.end(RespBodyBuilder.toError(RespCode.CODE_10500));
                return;
            }
            logger.info("accept : " + requestBody.toString());
            String LID = JsonUtil.getServiceIDBySef(4);
            resp.put("lid", LID);
            requestBody.put("lid", LID);
            vertx.eventBus().send("log.service.req", requestBody.copy().put("service", "network.refundback"));//记录日志
            DeliveryOptions options = new DeliveryOptions();
            options.setSendTimeout(Integer.valueOf(environment.getProperty("vertx.sendimeout", "10000")));
            vertx.eventBus().send("network.refundback", requestBody, options, res -> {
                if (res.succeeded()) {
                    resp.mergeIn(new JsonObject(res.result().body().toString()));
                } else {
                    logger.error("doRefundbackToorder error :" + res.cause().getMessage());
                    if (res.cause().getMessage().indexOf("No handlers for address") > -1) {
                        resp.mergeIn(new JsonObject(RespBodyBuilder.toError(RespCode.CODE_10500)));
                    } else {
                        resp.mergeIn(new JsonObject(RespBodyBuilder.toError(RespCode.CODE_10500)));
                    }
                }
                logger.info("doRefundbackToorder reply:" + resp.toString());
                vertx.eventBus().send("log.service.res", resp.copy().put("service", "network.refundback"));
                resp.remove("lid");
                response.end(resp.toString());
            });
        } catch (Exception e) {
            logger.error("doRefundbackToorder Error :" + e.getMessage());
            response.end(RespBodyBuilder.toError(RespCode.CODE_10500));
        }
    }

    private void doPaybackToorder(RoutingContext context) {
        HttpServerResponse response = context.response();
        response.putHeader("content-type", "application/json;charset=UTF-8");
        String method = context.request().method().name();
        logger.info("doPaybackToorder method=" + method);
        JsonObject resp = new JsonObject();
        logger.info("doPaybackToorder param=" + context.getBodyAsString());
        JsonObject requestBody = method.equals("POST") ? JsonUtil.parsePostBody(context.getBodyAsString()) : JsonUtil.convertMultiMap(context.request().params());
        try {
            if (requestBody == null) {
                response.end(RespBodyBuilder.toError(RespCode.CODE_10500));
                return;
            }
            logger.info("accept : " + requestBody.toString());
            String LID = JsonUtil.getServiceIDBySef(4);
            resp.put("lid", LID);
            requestBody.put("lid", LID);
            vertx.eventBus().send("log.service.req", requestBody.copy().put("service", "network.payback"));//记录日志
            DeliveryOptions options = new DeliveryOptions();
            options.setSendTimeout(Integer.valueOf(environment.getProperty("vertx.sendimeout", "10000")));
            //vertx.eventBus().send("network.backrecharge", requestBody, options, res -> {
            vertx.eventBus().send("network.payback", requestBody, options, res -> {
                if (res.succeeded()) {
                    resp.mergeIn(new JsonObject(res.result().body().toString()));
                } else {
                    logger.error("doPaybackToorder error :" + res.cause().getMessage());
                    if (res.cause().getMessage().indexOf("No handlers for address") > -1) {
                        resp.mergeIn(new JsonObject(RespBodyBuilder.toError(RespCode.CODE_10500)));
                    } else {
                        resp.mergeIn(new JsonObject(RespBodyBuilder.toError(RespCode.CODE_10500)));
                    }
                }
                logger.info("doPaybackToorder reply:" + resp.toString());
                vertx.eventBus().send("log.service.res", resp.copy().put("service", "network.payback"));
                resp.remove("lid");
                response.end(resp.toString());
            });
        } catch (Exception e) {
            logger.error("doPaybackToorder Error :" + e.getMessage());
            response.end(RespBodyBuilder.toError(RespCode.CODE_10500));
        }
    }

    private void doPrEventBusGateway(RoutingContext context) {
        HttpServerResponse response = context.response();
        response.putHeader("content-type", "application/json;charset=UTF-8");
        response.putHeader("Access-Control-Allow-Origin", "*");
        response.putHeader("Access-Control-Allow-Methods", "POST,GET");
        response.putHeader("Access-Control-Allow-Headers", "x-requested-with,content-type");
        String method = context.request().method().name();
        JsonObject resp = new JsonObject();
        JsonObject requestBody = method.equals("POST") ? context.getBodyAsJson() : JsonUtil.convertMultiMap(context.request().params());
        try {
            String channel = requestBody.containsKey("channel") ? requestBody.getString("channel") : "web";
            requestBody.put("channel", channel);
            String LID = JsonUtil.getServiceIDBySef(4);
            resp.put("lid", LID);
            requestBody.put("lid", LID);
            vertx.eventBus().send("log.service.req", requestBody);//记录日志
            DeliveryOptions options = new DeliveryOptions();
            options.setSendTimeout(Integer.valueOf(environment.getProperty("vertx.sendimeout", "10000")));
            vertx.eventBus().send(requestBody.getString("service"), requestBody, options, res -> {
                if (res.succeeded()) {
                    resp.mergeIn(new JsonObject(res.result().body().toString()));
                } else {
                    logger.error("error :" + res.cause().getMessage());
                    if (res.cause().getMessage().indexOf("No handlers for address") > -1) {
                        resp.mergeIn(new JsonObject(RespBodyBuilder.toError(RespCode.CODE_10500)));
                    } else {
                        resp.mergeIn(new JsonObject(RespBodyBuilder.toError(RespCode.CODE_10500)));
                    }
                }
                logger.info("reply:{}", resp.toString());
                vertx.eventBus().send("log.service.res", resp.copy().put("service", requestBody.getString("service")).put("phonenum", requestBody.getString("serialNumber")));
                resp.remove("lid");
                response.end(resp.toString());
            });
        } catch (Exception e) {
            logger.error("Error :{}", e.getMessage());
            vertx.eventBus().send("log.service.res", new JsonObject(RespBodyBuilder.toError(RespCode.CODE_10500)).put("service", requestBody.getString("service")).put("phonenum", requestBody.getString("serialNumber")));
            response.end(RespBodyBuilder.toError(RespCode.CODE_10500));
        }
    }

    private void doPrLongEventBusGateway(RoutingContext context) {
        HttpServerResponse response = context.response();
        response.putHeader("content-type", "application/json;charset=UTF-8");
        response.putHeader("Access-Control-Allow-Origin", "*");
        response.putHeader("Access-Control-Allow-Methods", "POST,GET");
        response.putHeader("Access-Control-Allow-Headers", "x-requested-with,content-type");
        String method = context.request().method().name();
        JsonObject resp = new JsonObject();
        JsonObject requestBody = method.equals("POST") ? context.getBodyAsJson() : JsonUtil.convertMultiMap(context.request().params());
        try {
            String channel = requestBody.containsKey("channel") ? requestBody.getString("channel") : "web";
            requestBody.put("channel", channel);
            String LID = JsonUtil.getServiceIDBySef(4);
            resp.put("lid", LID);
            requestBody.put("lid", LID);
            vertx.eventBus().send("log.service.req", requestBody);//记录日志
            DeliveryOptions options = new DeliveryOptions();
            options.setSendTimeout(Integer.valueOf(environment.getProperty("vertx.sendLongTmeout", "300000")));
            vertx.eventBus().send(requestBody.getString("service"), requestBody, options, res -> {
                if (res.succeeded()) {
                    resp.mergeIn(new JsonObject(res.result().body().toString()));
                } else {
                    logger.error("error :" + res.cause().getMessage());
                    if (res.cause().getMessage().indexOf("No handlers for address") > -1) {
                        resp.mergeIn(new JsonObject(RespBodyBuilder.toError(RespCode.CODE_10500)));
                    } else {
                        resp.mergeIn(new JsonObject(RespBodyBuilder.toError(RespCode.CODE_10500)));
                    }
                }
                logger.info("reply:" + resp.toString());
                vertx.eventBus().send("log.service.res", resp.copy().put("service", requestBody.getString("service")).put("phonenum", requestBody.getString("serialNumber")));
                resp.remove("lid");
                response.end(resp.toString());
            });
        } catch (Exception e) {
            logger.error("Error :" + e.getMessage());
            vertx.eventBus().send("log.service.res", new JsonObject(RespBodyBuilder.toError(RespCode.CODE_10500)).put("service", requestBody.getString("service")).put("phonenum", requestBody.getString("serialNumber")));
            response.end(RespBodyBuilder.toError(RespCode.CODE_10500));
        }
    }

    private void doBlackCardNotify(RoutingContext context) {
        HttpServerResponse response = context.response();
        response.putHeader("content-type", "application/json;charset=UTF-8");
        response.putHeader("Access-Control-Allow-Origin", "*");
        response.putHeader("Access-Control-Allow-Methods", "POST,GET");
        response.putHeader("Access-Control-Allow-Headers", "x-requested-with,content-type");
        String method = context.request().method().name();
        JsonObject resp = new JsonObject();
        System.out.println(context.request().params());
        JsonObject requestBody = method.equals("POST") ? context.getBodyAsJson() : JsonUtil.convertMultiMap(context.request().params());
        try {
            String LID = JsonUtil.getServiceIDBySef(4);
            resp.put("lid", LID);
            requestBody.put("lid", LID);
            DeliveryOptions options = new DeliveryOptions();
            options.setSendTimeout(Integer.valueOf(environment.getProperty("vertx.sendtimeout", "300000")));
            vertx.eventBus().send("blackcard.writenotify", requestBody, options, res -> {
                if (res.succeeded()) {
                    resp.mergeIn(new JsonObject(res.result().body().toString()));
                } else {
                    logger.error("error :" + res.cause().getMessage());
                    resp.put("resultcode", "-1").put("resultdes", "error");
                }
                logger.info("reply:" + resp.toString());
                resp.remove("lid");
                response.end(resp.toString());
            });
        } catch (Exception e) {
            logger.error("error :" + e.getMessage());
            resp.put("resultcode", "-1").put("resultdes", "error");
            response.end(resp.encode());
        }
    }

    private void reqError(HttpServerRequest request, int code, String logMessage) {
        logger.error(logMessage);
        request.response()
                .putHeader("content-type", "application/json;charset=utf-8")
                .putHeader("Access-Control-Allow-Origin", "*")
                .putHeader("Access-Control-Allow-Credentials", "true")
                .putHeader("Content-Disposition", "attachment")
                .setStatusCode(code)
                .end();
    }

}
